/**
  ******************************************************************************
  * @file    GPIO/IOToggle/stm32f10x_it.c 
  * @author  MCD Application Team
  * @version V3.6.0
  * @date    20-September-2021
  * @brief   Main Interrupt Service Routines.
  *          This file provides template for all exceptions handler and peripherals
  *          interrupt service routine.
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2011 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */

/* Includes ------------------------------------------------------------------*/
#include "stm32f10x_it.h"

/** @addtogroup STM32F10x_StdPeriph_Examples
  * @{
  */

/** @addtogroup GPIO_IOToggle
  * @{
  */

/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
uint8_t cmd[8] = {0};
uint8_t cmdIndex = 0;
uint8_t memdone = 0;

// 用于ESP8266首发命令的变量 
// extern uint32_t isCmd;
extern uint8_t espRecvData[16];
extern uint8_t espSendData[16];
// extern uint8_t espCmd[16];
// extern uint8_t espResp[16];
uint8_t espCmd[16];
uint8_t espResp[16];
uint8_t type, num, action, other;

/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/

/******************************************************************************/
/*            Cortex-M3 Processor Exceptions Handlers                         */
/******************************************************************************/

/**
  * @brief  This function handles NMI exception.
  * @param  None
  * @retval None
  */
void NMI_Handler(void)
{
}

/**
  * @brief  This function handles Hard Fault exception.
  * @param  None
  * @retval None
  */
void HardFault_Handler(void)
{
  /* Go to infinite loop when Hard Fault exception occurs */
  while (1)
  {
  }
}

/**
  * @brief  This function handles Memory Manage exception.
  * @param  None
  * @retval None
  */
void MemManage_Handler(void)
{
  /* Go to infinite loop when Memory Manage exception occurs */
  while (1)
  {
  }
}

/**
  * @brief  This function handles Bus Fault exception.
  * @param  None
  * @retval None
  */
void BusFault_Handler(void)
{
  /* Go to infinite loop when Bus Fault exception occurs */
  while (1)
  {
  }
}

/**
  * @brief  This function handles Usage Fault exception.
  * @param  None
  * @retval None
  */
void UsageFault_Handler(void)
{
  /* Go to infinite loop when Usage Fault exception occurs */
  while (1)
  {
  }
}

/**
  * @brief  This function handles SVCall exception.
  * @param  None
  * @retval None
  */
void SVC_Handler(void)
{
}

/**
  * @brief  This function handles Debug Monitor exception.
  * @param  None
  * @retval None
  */
void DebugMon_Handler(void)
{
}

/**
  * @brief  This function handles PendSV_Handler exception.
  * @param  None
  * @retval None
  */
void PendSV_Handler(void)
{
}

/**
  * @brief  This function handles SysTick Handler.
  * @param  None
  * @retval None
  */
void SysTick_Handler(void)
{
}

/******************************************************************************/
/*                 STM32F10x Peripherals Interrupt Handlers                   */
/*  Add here the Interrupt Handler for the used peripheral(s) (PPP), for the  */
/*  available peripheral interrupt handler's name please refer to the startup */
/*  file (startup_stm32f10x_xx.s).                                            */
/******************************************************************************/

/**
  * @brief  This function handles PPP interrupt request.
  * @param  None
  * @retval None
  */
/*void PPP_IRQHandler(void)
{
}*/

/**
  * @}
  */

/**
  * @}
  */

// 用户重写的中断处理函数
// 中断处理函数的一般写法
// 1. 找到本通道对应的函数, 将其声明和定义写在_it文件
//    1.1 注意其参数和返回值都应该是void
// 2. 先使用XXX_GetITStatus(), 判断是哪种中断源
// 3. 在对应的判断内, 使用XXX_ClearITPendingBits清除对应标志位
// 4. 编写自己的代码, 执行需要做的操作
// 如果不清楚清除, 会导致其无限中断
void USART1_IRQHandler(void)
{
  // 实现以下功能: 接收到"open"字符串, 会开灯
  // 接收到"close"字符串, 会关灯"

  // 先判断是RXNE
  if (SET == USART_GetITStatus(USART1, USART_IT_RXNE))
  {
    // 如果是RXNE即有数据可用
    cmd[cmdIndex++] = USART_ReceiveData(USART1); // 此句操作会清除RXNE标志位
  }
  if (SET == USART_GetITStatus(USART1, USART_IT_IDLE))
  {
    // IDEL的清除: 先读sr, 再读dr
    // 在前一句GetITStatus已经读取过SR,
    // 此处可以手动加一句无实际用途的读取DR动作来触发清理
    USART_ReceiveData(USART1);
    
    if (!strcmp((const char *)cmd, "open"))
      RGB_greenOn();
    else if (!strcmp((const char *)cmd, "close"))
      RGB_greenOff();
    // 命令数组复位
    memset(cmd, 0, sizeof(cmd));
    cmdIndex = 0;
  }
}

void EXTI0_IRQHandler(void)
{
  // 判断是否是PA0, 而非PB~PG等端口组
  if (SET == GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0))
  {
    // clear
    EXTI_ClearITPendingBit(EXTI_Line0);
    // 事件
    // lightState = !lightState;
    // if(lightState)
    //   RGB_redOn();
    // else
    //   RGB_redOff();
    RGB_redToggle();
  }
}

void TIM6_IRQHandler(void)
{
  if(SET == TIM_GetITStatus(TIM6, TIM_IT_Update))
  {
    // 先清除此中断等待标志位
    TIM_ClearITPendingBit(TIM6, TIM_IT_Update);
    // 做需要的操作
    RGB_redToggle();
  }
}

void DMA1_Channel5_IRQHandler(void)
{
  if(SET == DMA_GetITStatus(DMA1_IT_TC5))
  {
    DMA_ClearITPendingBit(DMA1_IT_TC5);
    memdone = 1;
  }
}

/**
 * @brief ESP8266的串口中断处理函数
 * 
 */
void USART3_IRQHandler(void)
{
  if(SET == USART_GetITStatus(USART3, USART_IT_IDLE))
  {
    // USART_ClearITPendingBit(USART3, USART_IT_IDLE);
    // IDEL的清除: 先读sr, 再读dr
    // 在前一句GetITStatus已经读取过SR,
    // 此处可以手动加一句无实际用途的读取DR动作来触发清理
    USART_ReceiveData(USART3);
    // ------------
    // 1. 提醒主逻辑, 已经收到完整命令, 可以处理并反馈了
    memset(espCmd, 0, 16);
    memcpy(espCmd, espRecvData, 16);
    memset(espRecvData, 0, 16);
    
    sscanf((const char *)espCmd, "%1d%1d%1d%d",
           (int *)&type,
           (int *)&num,
           (int *)&action,
           (int *)&other);

    if (type == 1)
    {
      if (action == 1)
        LIGHT_setColor(255, 255, 0);
      else if (action == 0)
        LIGHT_setColor(255, 0, 0);
    }
    else if (type == 2)
    {
      if (action == 1)
        LIGHT_setColor(0, 0, 255);
      else if (action == 0)
        LIGHT_setColor(255, 0, 255);
    }
    else if (type == 3)
    {
      if (action == 1)
        LIGHT_setColor(0, 255, 0);
      else if (action == 0)
        LIGHT_setColor(255, 255, 255);
    }
    else
      LIGHT_setColor(50, 100, 150);

    // 在透传模式下直接发送字符串
    char devStr[32];
    sprintf(devStr, " Status: %d%d%d", type, num, action);
    const char *data = (const char *)devStr;
    while (*data)
    {
      USART_SendData(USART3, *data++);
      while (USART_GetFlagStatus(USART3, USART_FLAG_TXE) == RESET)
        ;
    }
    // 发送换行符以便服务器区分不同消息
    USART_SendData(USART3, '\r');
    while (USART_GetFlagStatus(USART3, USART_FLAG_TXE) == RESET)
      ;
    USART_SendData(USART3, '\n');
    while (USART_GetFlagStatus(USART3, USART_FLAG_TXE) == RESET)
      ;

    // 处理完之后, 命令本身清零, 等待下一次收到命令
    memset(espCmd, 0, 16);

    // 2. 重置DMA, 重新开始接收并存储
    DMA_Cmd(DMA1_Channel3, DISABLE);
    DMA_SetCurrDataCounter(DMA1_Channel3, 16);
    DMA_Cmd(DMA1_Channel3, ENABLE);

    // 检查溢出错误
    if (USART_GetFlagStatus(USART3, USART_FLAG_ORE) != RESET)
    {
      USART_ClearFlag(USART3, USART_FLAG_ORE);
      USART_ReceiveData(USART3); // 清空错误数据
    }
  }
}
